﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CSharp.Libs.Koc;
using System.Collections;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input;

namespace CSharp.Libs.WPF.UserControls
{
    public class MapViewViewModel : ViewModelBase
    {
        #region declarations
        private Kernel _KRNL = null;

        private RelayCommand _rcSetCity1 = null;
        private RelayCommand _rcSetCity2 = null;
        private RelayCommand _rcResetToDefaultColors = null;

        private MapViewMarkCityItem _mciCity1 = new MapViewMarkCityItem();
        private MapViewMarkCityItem _mciCity2 = new MapViewMarkCityItem();

        private RenderTargetBitmap _rtbBackground = new RenderTargetBitmap(750, 750, 96, 96, PixelFormats.Pbgra32);
        private RenderTargetBitmap _rtbCoordLayer = new RenderTargetBitmap(750, 750, 96, 96, PixelFormats.Pbgra32);
        private RenderTargetBitmap _rtbMarkLayer = new RenderTargetBitmap(750, 750, 96, 96, PixelFormats.Pbgra32);
        private RenderTargetBitmap _rtbTopLayer = new RenderTargetBitmap(750, 750, 96, 96, PixelFormats.Pbgra32);

        private ArrayList _KIs = null;
        private ArrayList _aryMarkLayer = new ArrayList();

        private MapViewKoordItem _KI = new MapViewKoordItem("");

        private String _strSeekPlayerName = "";
        private Int32 _intCurrentX = 0;
        private Int32 _intCurrentY = 0;
        private Int32 _intRightClickX = 0;
        private Int32 _intRightClickY = 0;
        private Int32 _intRadius = 15;
        private Double _dblDistanceC1C2 = 0;
        private Boolean _fAutoMarkPlayerCities = true;

        private SolidColorBrush _scbBackground1 = Brushes.White;
        private SolidColorBrush _scbBackground2 = new SolidColorBrush(Color.FromArgb(255, 245, 245, 245));
        #endregion



        #region constructor / terminator
        public MapViewViewModel(
            Kernel KRNL)
        {
            _KRNL = KRNL;

            _DrawBackGround();
        }

        ~MapViewViewModel()
        {
            _rtbBackground = null;
        }
        #endregion



        #region private functions
        #region drawing
        public void _DrawBackGround()
        {
            DrawingVisual dv = new DrawingVisual();
            using(DrawingContext dc = dv.RenderOpen())
            {
                SolidColorBrush BR = Brushes.Wheat;

                for(Int32 X=0; X < 750; X += 150)
                {
                    for(Int32 Y=0; Y < 750; Y += 150)
                    {
                        if(BR == _scbBackground1)
                        {
                            BR = _scbBackground2;
                        }
                        else
                        {
                            BR = _scbBackground1;
                        }

                        dc.DrawRectangle(BR, null, new Rect(X, Y, 150, 150));
                    }
                }

                dc.DrawRectangle(Brushes.Transparent, null, new Rect(300, 300, 150, 150));

                dc.Close();
            }

            _rtbBackground.Render(dv);
        }

        private void _ShowCoords(
            ArrayList KoordItems)
        {
            DrawingVisual dv = new DrawingVisual();

            using(DrawingContext dc = dv.RenderOpen())
            {
                foreach (MapViewKoordItem KI in KoordItems)
                {
                    dc.DrawRectangle(KI.Color, null, new Rect((Double)KI.X, (Double)KI.Y, 1, 1));
                }

                dc.Close();
            }

            _rtbCoordLayer.Render(dv);
        }

        /// <summary>_MarkCoords</summary>
        /// <history>03.08.2011 redesigned old function</history>
        /// <history>05.08.2011 added painting of a line in between City1 and City2</history>
        private void _MarkCoords()
        {
            if (_KIs != null)
            {
                //first off clear mark layer bitmap and array
                _rtbMarkLayer.Clear();
                _aryMarkLayer.Clear();

                //Add items to MarkArray
                _AddKIsToMarkArray();
                
                //create markings on mark layer bitmap
                if (_aryMarkLayer.Count != 0)
                {
                    //create DrawingVisual and DrawingContext
                    DrawingVisual dv = new DrawingVisual();
                    using (DrawingContext dc = dv.RenderOpen())
                    {
                        //if aplicable, draw distance line
                        if (_mciCity1.CityName != "" &&
                            _mciCity2.CityName != "")
                        {
                            Point P1 = _GetLinePoint(.1, _mciCity1.CityX, _mciCity1.CityY, _mciCity2.CityX, _mciCity2.CityY);
                            Point P2 = _GetLinePoint(.9, _mciCity1.CityX, _mciCity1.CityY, _mciCity2.CityX, _mciCity2.CityY);
                            dc.DrawLine(new Pen(Brushes.Green, 0.5), P1, P2);
                        }

                        //loop through mark array
                        foreach (MapViewKoordItem KI in _aryMarkLayer)
                        {
                            dc.DrawEllipse(null, new Pen(KI.Color, 1), new Point((Double)KI.X, (Double)KI.Y), _intRadius, _intRadius);
                        }

                        dc.Close();
                    }

                    _rtbMarkLayer.Render(dv);
                }
            }
        }

        /// <summary>_CheckCoords</summary>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <history>04.08.2011 modified: extracted method _GetKiByKoords</history>
        private void _CheckCoords(
            Int32 X,
            Int32 Y)
        {
            if(_KIs != null)
            {
                _KI = _GetKiByCoords(X, Y);

                if (_fAutoMarkPlayerCities)
                {
                    _MarkCoords();
                }

                OnPropertyChanged("CurrentCoords");
                OnPropertyChanged("CurrentPlayer");
                OnPropertyChanged("CurrentMight");
                OnPropertyChanged("CurrentAlliance");
                OnPropertyChanged("CurrentCity");
                OnPropertyChanged("CurrentOnlineStatus");
                OnPropertyChanged("CurrentLastLogin");
            }
        }

        #region sub functions
        /// <summary>_SetDefaultBackground</summary>
        /// <history>04.08.2011</history>
        private void _SetDefaultBackground()
        {
            try
            {
                _scbBackground1 = Brushes.White;
                _scbBackground2 = new SolidColorBrush(Color.FromArgb(255, 245, 245, 245));
                _DrawBackGround();
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_GetKiByCoords</summary>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <returns></returns>
        /// <history>04.08.2011</history>
        private MapViewKoordItem _GetKiByCoords(
            Int32 X,
            Int32 Y)
        {
            try
            {
                foreach (MapViewKoordItem KI in _KIs)
                {
                    if (KI.X == X && KI.Y == Y)
                    {
                        _KI = KI;
                        return _KI;
                    }
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            return new MapViewKoordItem("");
        }

        /// <summary>_AddKIsToMarkArrayByPlayerName</summary>
        /// <history>04.08.2011</history>
        private void _AddKIsToMarkArray()
        {
            try
            {
                //run through coord collection to find seeked players / cities
                //to build up mark array
                foreach (MapViewKoordItem KI in _KIs)
                {
                    if (KI.PlayerName == _strSeekPlayerName ||
                        KI.PlayerName == _KI.PlayerName)
                    {
                        _aryMarkLayer.Add(KI);
                    }

                    if (_mciCity1.CityName != "")
                    {
                        if (KI.CityName == _mciCity1.CityName)
                        {
                            _aryMarkLayer.Add(KI);
                        }
                    }

                    if (_mciCity2.CityName != "")
                    {
                        if (KI.CityName == _mciCity2.CityName)
                        {
                            _aryMarkLayer.Add(KI);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_GetLinePoint</summary>
        /// <param name="T"></param>
        /// <param name="X1"></param>
        /// <param name="Y1"></param>
        /// <param name="X2"></param>
        /// <param name="Y2"></param>
        /// <returns></returns>
        /// <history>05.08.2011 credits to AThu</history>
        private Point _GetLinePoint(
            Double T,
            Double X1,
            Double Y1,
            Double X2,
            Double Y2)
        {
            try
            {
                Double dblX = X1 * (1 - T) + X2 * T;
                Double dblY = Y1 * (1 - T) + Y2 * T;
                return new Point(dblX, dblY);
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            return new Point(-1, -1);
        }
        #endregion
        #endregion

        #region seeking
        /// <summary>_SetCity1</summary>
        /// <history>04.08.2011</history>
        private void _SetCity1()
        {
            try
            {
                MapViewKoordItem kiCity1 = _GetKiByCoords(_intRightClickX, _intRightClickY);
                if (kiCity1 != null)
                {
                    _mciCity1.CityName = kiCity1.CityName;
                    _mciCity1.CityX = kiCity1.X;
                    _mciCity1.CityY = kiCity1.Y;

                    _CalcDistanceCity1City2();
                }
            }
            catch(Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            OnPropertyChanged("City1Name");
        }

        /// <summary>_SetCity2</summary>
        /// <history>04.08.2011</history>
        private void _SetCity2()
        {
            try
            {
                MapViewKoordItem kiCity2 = _GetKiByCoords(_intRightClickX, _intRightClickY);
                if (kiCity2 != null)
                {
                    _mciCity2.CityName = kiCity2.CityName;
                    _mciCity2.CityX = kiCity2.X;
                    _mciCity2.CityY = kiCity2.Y;

                    _CalcDistanceCity1City2();
                }
            }
            catch(Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            OnPropertyChanged("City2Name");
        }

        /// <summary>_CalcDistanceCity1City2</summary>
        /// <history>04.08.2011</history>
        private void _CalcDistanceCity1City2()
        {
            try
            {
                if (_mciCity1.CityName != "" &&
                    _mciCity2.CityName != "")
                {
                    _dblDistanceC1C2 = _GetDistance(
                        _mciCity1.CityX, _mciCity1.CityY,
                        _mciCity2.CityX, _mciCity2.CityY);
                }
                else
                {
                    _dblDistanceC1C2 = 0;
                }

                OnPropertyChanged("DistanceC1C2");
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }
        #endregion

        #region help functions
        /* usage:
         *  return distance (city.x, city.y, tileX, tileY);
          
           function distance (d, f, c, e) 
           {
              var a = 750;
              var g = a / 2;
              
              var b = Math.abs(c - d);
         
              if (b > g)
              {
                b = a - b;
              }
              
              var h = Math.abs(e - f);
          
              if (h > g)
              {
                h = a - h;
              }
         
              return Math.round(100 * Math.sqrt(b * b + h * h)) / 100;
            };
         */
        private Double _GetDistance(
            Int32 d, Int32 f,
            Int32 c, Int32 e)
        {
            Int32 a = 750;
            Int32 g = a / 2;

            Int32 b = Math.Abs(c - d);

            if(b > g)
            {
                b = a - b;
            }

            Int32 h = Math.Abs(e - f);

            if(h > g)
            {
                h = a - h;
            }

            return Math.Round(100 * Math.Sqrt(b * b + h * h)) / 100;
        }
        #endregion
        #endregion



        #region interface
        #region properties
        #region bitmaps
        public SolidColorBrush BackgroundColor1
        {
            get
            {
                return _scbBackground1;
            }
            set
            {
                _scbBackground1 = value;
                _DrawBackGround();
            }
        }

        public SolidColorBrush BackgroundColor2
        {
            get
            {
                return _scbBackground2;
            }
            set
            {
                _scbBackground2 = value;
                _DrawBackGround();
            }
        }

        public ICommand ResetToDefaultColors
        {
            get
            {
                if (_rcResetToDefaultColors == null)
                {
                    _rcResetToDefaultColors = new RelayCommand(
                        param => this._SetDefaultBackground(),
                        param => this.CanResetToDefaultColors);
                }
                return _rcResetToDefaultColors;
            }
        }
        public Boolean CanResetToDefaultColors
        {
            get
            {
                return true;
            }
        }

        public RenderTargetBitmap MapViewBackground
        {
            get
            {
                return _rtbBackground;
            }
        }

        public RenderTargetBitmap MapViewCoordLayer
        {
            get
            {
                return _rtbCoordLayer;
            }
        }

        public RenderTargetBitmap MapViewMarkLayer
        {
            get
            {
                return _rtbMarkLayer;
            }
        }
        
        public RenderTargetBitmap MapViewTopLayer
        {
            get
            {
                return _rtbTopLayer;
            }
        }
        #endregion

        #region side data
        public String CurrentCoords
        {
            get
            {
                if (_KI.PlayerName != "")
                {
                    return _KI.X.ToString() + "," + _KI.Y.ToString();
                }
                return "";
            }
        }

        public String CurrentPlayer
        {
            get
            {
                return _KI.PlayerName;
            }
        }

        public String CurrentMight
        {
            get
            {
                return _KI.PlayerMight;
            }
        }

        public String CurrentAlliance
        {
            get
            {
                return _KI.Alliance;
            }
        }

        public String CurrentCity
        {
            get
            {
                return _KI.CityName;
            }
        }

        public String CurrentOnlineStatus
        {
            get
            {
                return _KI.OnlineStatus;
            }
        }

        public String CurrentLastLogin
        {
            get
            {
                return _KI.LastLogin;
            }
        }

        public Int32 CurrentX
        {
            get
            {
                return _intCurrentX;
            }
            set
            {
                if (value != _intCurrentX)
                {
                    _intCurrentX = value;
                    OnPropertyChanged("CurrentX");
                    _CheckCoords(_intCurrentX, _intCurrentY);
                }
            }
        }

        public Int32 CurrentY
        {
            get
            {
                return _intCurrentY;
            }
            set
            {
                if (value != _intCurrentY)
                {
                    _intCurrentY = value;
                    OnPropertyChanged("CurrentY");
                    _CheckCoords(_intCurrentX, _intCurrentY);
                }
            }
        }
        #endregion

        #region search and mark
        public Int32 RightClickX
        {
            get
            {
                return _intRightClickX;
            }
            set
            {
                _intRightClickX = value;
            }
        }

        public Int32 RightClickY
        {
            get
            {
                return _intRightClickY;
            }
            set
            {
                _intRightClickY = value;
            }
        }

        public ICommand SetCity1
        {
            get
            {
                if(_rcSetCity1 == null)
                {
                    _rcSetCity1 = new RelayCommand(
                        param => this._SetCity1(),
                        param => this.CanSetCity1);
                }
                return _rcSetCity1;
            }
        }
        public Boolean CanSetCity1
        {
            get
            {
                return true;//                _KRNL.UH.URLAllianceGetOtherInfo.URLMaybeValid;
            }
        }

        public ICommand SetCity2
        {
            get
            {
                if(_rcSetCity2 == null)
                {
                    _rcSetCity2 = new RelayCommand(
                        param => this._SetCity2(),
                        param => this.CanSetCity2);
                }
                return _rcSetCity2;
            }
        }
        public Boolean CanSetCity2
        {
            get
            {
                return true;//                _KRNL.UH.URLAllianceGetOtherInfo.URLMaybeValid;
            }
        }

        public String SeekPlayerName
        {
            get
            {
                return _strSeekPlayerName;
            }
            set
            {
                _strSeekPlayerName = value;
                _MarkCoords();
            }
        }

        public String City1Name
        {
            get
            {
                return _mciCity1.CityName;
            }
        }

        public String City2Name
        {
            get
            {
                return _mciCity2.CityName;
            }
        }

        public String DistanceC1C2
        {
            get
            {
                return _dblDistanceC1C2.ToString("0.00");
            }
        }

        public Boolean AutoMarkPlayerCities
        {
            get
            {
                return _fAutoMarkPlayerCities;
            }
            set
            {
                _fAutoMarkPlayerCities = value;
            }
        }

        public Int32 MarkRadius
        {
            get
            {
                return _intRadius;
            }
            set
            {
                if (value > 0 && value < 750)
                {
                    _intRadius = value;
                }
            }
        }
        #endregion
        #endregion

        #region methods
        public void ShowCoords(
            ArrayList KoordItems)
        {
            _rtbCoordLayer.Clear();
            _rtbMarkLayer.Clear();

            _KIs = KoordItems;
            _ShowCoords(_KIs);
        }
        #endregion
        #endregion
    }
}
